package com.github.cosycode.imgtool.rule;

import com.github.cosycode.common.ext.bean.DoubleBean;
import com.github.cosycode.common.util.io.FileSystemUtils;
import com.github.cosycode.common.util.otr.PrintTool;
import com.github.cosycode.imgtool.tool.ImageCheckTool;
import com.github.cosycode.imgtool.util.FileUtils;
import com.github.cosycode.imgtool.util.LogUtils;
import com.github.cosycode.imgtool.util.PathUtils;
import lombok.Data;
import lombok.Getter;
import lombok.NonNull;

import java.io.File;
import java.io.FileNotFoundException;
import java.util.*;

/**
 * 设计理念
 * 将统一的数据源 以及对应的数据源的相关逻辑, 集成到一个类里面.
 */
@Data
public class MarkdownRepairSource {

    /**
     * markdown 文件列表
     */
    private final Set<String> markdownFileSet = new TreeSet<>();
    /**
     * 图片文件列表
     */
    private final Set<String> picFileSet = new TreeSet<>();

    /**
     * 查询是否有重复的文件名
     * <p>
     * replace by {@link MarkdownRepairSource#analyzeRepeatFileName(Set)} (java.util.Set)}
     *
     * @param set 文件路径集合
     * @return 重复数量, 至少删除掉该数量的文件剩下的文件则全部不重复(假如有两个文件相同, 则返回 1, n 个文件相同, 返回 n-1)
     */
    @Deprecated
    public static int checkRepeatFilename(Set<String> set) {
        int cnt = 0;
        Map<String, DoubleBean<Integer, String>> pathMap = new HashMap<>();
        for (String item : set) {
            int s = Math.max(item.lastIndexOf('\\'), item.lastIndexOf('/'));
            s = Math.max(s, 0);
            String key = item.substring(s);
            DoubleBean<Integer, String> doubleBean = pathMap.get(key);
            if (doubleBean == null) {
                pathMap.put(key, DoubleBean.of(1, item));
            } else {
                cnt++;
                if (doubleBean.getO1().equals(1)) {
                    PrintTool.warn("[repeat] {} {} -> {}", 1, key, doubleBean.getO2());
                }
                doubleBean.setO1(doubleBean.getO1() + 1);
                doubleBean.setO2(item);
                PrintTool.warn("[repeat] {} {} -> {}", doubleBean.getO1(), key, doubleBean.getO2());
            }
        }
        return cnt;
    }

    public static MarkdownRepairSource singleProjectSource(@NonNull String projectPath) throws FileNotFoundException {
        MarkdownRepairSource source = new MarkdownRepairSource();
        File file = new File(projectPath);
        source.addMarkdownFile(file);
        source.addImgFile(file);
        return source;
    }

    /**
     * 查询是否有重复的文件名
     *
     * @param set 文件路径集合
     * @return DoubleBean<Map < String, String>, Map<String, List<String>>>
     * <p>
     */
    @SuppressWarnings("java:S117")
    public static RepeatFileNameReport analyzeRepeatFileName(Set<String> set) {
        // 独一无二的名称列表
        Map<String, String> name$Path$Map = new HashMap<>();
        // 若有名称重复, 才存到该列表里面.
        Map<String, List<String>> name$PathList$Map = new HashMap<>();
        for (String path : set) {
            int s = Math.max(path.lastIndexOf('\\'), path.lastIndexOf('/'));
            String key = path.substring(s + 1);
            String value = name$Path$Map.get(key);
            if (value == null) {
                name$Path$Map.put(key, path);
            } else {
                List<String> list = name$PathList$Map.computeIfAbsent(key, k -> {
                    List<String> l = new ArrayList<>();
                    l.add(value);
                    return l;
                });
                list.add(path);
            }
        }
        for (String key : name$PathList$Map.keySet()) {
            name$Path$Map.remove(key);
        }
        return new RepeatFileNameReport(name$Path$Map, name$PathList$Map);
    }

    public void addMarkdownFile(@NonNull File file) throws FileNotFoundException {
        file = PathUtils.getCanonicalPathFile(file);
        FileSystemUtils.findFileFromDir(file, f -> f.getName().endsWith(".md"), true, f -> markdownFileSet.add(f.getAbsolutePath()));
    }

    public void addImgFile(@NonNull File file) throws FileNotFoundException {
        file = PathUtils.getCanonicalPathFile(file);
        FileSystemUtils.findFileFromDir(file, ImageCheckTool::isImage, true, f -> picFileSet.add(f.getAbsolutePath()));
    }

    /**
     * <p>
     * Map<String, String>: fileName, filePath => 一一对应, 名称重复
     * Map<String, List<String>: fileName, filePathList => 若有名称重复, 才存到该列表里面.
     * </p>
     */
    @Getter
    public static class RepeatFileNameReport {
        private final Map<String, String> uniqueNameMap;
        /**
         * name$pathList$map
         */
        private final Map<String, List<String>> repeatNameListMap;

        public RepeatFileNameReport(Map<String, String> uniqueNameMap, Map<String, List<String>> repeatNameListMap) {
            this.uniqueNameMap = uniqueNameMap;
            this.repeatNameListMap = repeatNameListMap;
        }

        public void printLog() {
            if (repeatNameListMap.isEmpty()) {
                PrintTool.debug("[没有重复文件名]: 文件数量: {}", uniqueNameMap.size());
            } else {
                int total = uniqueNameMap.size();
                final int repeatKeyCnt = repeatNameListMap.size();
                int index = 0;
                for (Map.Entry<String, List<String>> entry : repeatNameListMap.entrySet()) {
                    index += 1;
                    List<String> value = entry.getValue();
                    total += value.size();
                    String fileName = entry.getKey();
                    PrintTool.info("[重复条目] [{}/{}] ==> 文件名: {}", index, repeatKeyCnt, fileName);
                    for (String link : value) {
                        PrintTool.info("  ==> 文件名: {}, link: {}", fileName, link);
                    }
                }
                PrintTool.info("[发现重复文件名] 文件总数: {}, 没有重复的文件名数量: {}, 重复的文件条目: {}",
                        total, uniqueNameMap.size(), repeatNameListMap.size());
            }
        }

        public void clearRepeatFile(boolean dryRun) {
            int size = repeatNameListMap.size();
            int ord = 0;
            for (Map.Entry<String, List<String>> entry : repeatNameListMap.entrySet()) {
                LogUtils.logEvent(() -> {
                    FileUtils.clearRepeatFileByMd5(entry.getValue(), dryRun);
                }, "[条目: {}/{}], fileName: {}", ++ord, size, entry.getKey());
            }
        }
    }

}
